#ifndef __FRAME_COMMON__
#define __FRAME_COMMON__
#include <memory>
#include <functional>

namespace FrameCommon{
    typedef enum{
        Invalid = -1,
        H264,
        H265,
        AAC,
        G711A,
        G711U,
        Opus,
	    L16,
	    VP8,
	    VP9,
	    AV1,
        MAX
    }CodecId;

    struct VideoFormat{
        uint16_t type;
        uint16_t BitRate;
        uint16_t Width;
        uint16_t Height;
        uint16_t Fps;
        uint16_t GOP;
        uint	 reserved[5];
        VideoFormat():type(0),BitRate(0),Width(0),Height(0),Fps(0),GOP(0),reserved{0}{ }
    };

    struct AudioFormat{
        uint16_t channel;
        uint16_t depth;
        uint32_t sampleRate;
        AudioFormat():channel(1),sampleRate(44100),depth(16){ }
    };

    class Frame{
    public:
        using Ptr = std::shared_ptr<Frame>;
        static Ptr CreateFrame(CodecId codec, char *data, int size, uint64_t dts, 
        uint64_t pts, bool is_key, uint64_t samples, size_t prefix_size = 0,
        bool is_ConfigFrame = false){
            return std::make_shared<Frame>(codec, data, size, dts, pts, is_key, samples, prefix_size, is_ConfigFrame);
        }

        Frame(CodecId codec, char *data, int size, uint64_t dts, 
            uint64_t pts, bool is_key, uint64_t samples, size_t prefix_size = 0, 
            bool is_ConfigFrame = false):m_codecId(codec), 
            m_data(data), m_data_size(size), m_dts(dts), m_pts(pts),
            m_is_key(is_key),m_samples(samples), m_prefix_size(prefix_size), 
            m_is_configFrame(is_ConfigFrame){

        }
    

        char *data() const{return m_data;}
        size_t size() const{return m_data_size;}
        uint64_t dts() const{return m_dts;}
        uint64_t pts() const{return m_pts;}
        size_t prefixSize() const {return m_prefix_size;}
        bool keyFrame() const {return m_is_key;}
        uint64_t smpls() const { return m_samples; }
        bool configFrame() const {return m_is_configFrame;}
        bool isVideo() const{
            if(m_codecId == H264 || m_codecId == H265) return true;
            return false;
        }
        bool isAudio() const{
            if(m_codecId == AAC || m_codecId == G711A || m_codecId == G711U) return true;
            return false;
        }
        CodecId codecId() const {return m_codecId;}

    private:
        CodecId m_codecId; 
        char *m_data;         
        int m_data_size;      
        uint64_t m_dts;       
        uint64_t m_pts;        
        bool m_is_key;         
        bool m_is_configFrame;
        uint64_t m_samples;
        size_t m_prefix_size;
    };

    using frame_callback_func = std::function<void (const Frame::Ptr&)>;
    using stop_callback_func = std::function<void ()>;
    
    class MediaChannel{
    public:
        using Ptr = std::shared_ptr<MediaChannel>;
        virtual bool Start(void *call_this, frame_callback_func callback) = 0;
        virtual bool Stop() = 0;
        virtual bool SetIFrame() = 0;
 	    virtual bool GetVideoFormat(VideoFormat& format) = 0;
    protected:
        MediaChannel(int video, int audio = 0):m_video(video), m_audio(audio){
        }
        virtual ~MediaChannel(){
        }
        int m_video;
        int m_audio;
    };

    class MediaChannelFinder{
    public:
        using Ptr = std::shared_ptr<MediaChannelFinder>;
        virtual MediaChannel::Ptr GetChannel(int video, int audio = 0) = 0;
        virtual ~MediaChannelFinder(){};
        MediaChannelFinder(){};
    };


    class StreamPlayer{
    public:
        using Ptr = std::shared_ptr<StreamPlayer>;
        virtual bool Start(frame_callback_func callback, stop_callback_func stop_callback) = 0;
        virtual bool Stop() = 0;
        const std::string& Url(){return m_url;}
        bool IsRtspTcp(){return m_isRtspTcp;}
    protected:
        StreamPlayer(const std::string& stream_url, bool isRtspTcp = false):m_url(stream_url),
        m_isRtspTcp(isRtspTcp){
        }
        virtual ~StreamPlayer(){};
        std::string m_url;
        bool m_isRtspTcp;
    };

    class StreamPlayCreater{
    public:
        using Ptr = std::shared_ptr<StreamPlayCreater>;
        virtual StreamPlayer::Ptr CreateStreamPlayer(const std::string& stream_url, 
        bool isRtspTcp = false) = 0;
        virtual ~StreamPlayCreater(){};
    };

    class Mp4Player{
    public:
        using Ptr = std::shared_ptr<Mp4Player>;

        Mp4Player(){

        }
        virtual ~Mp4Player(){

        }
        virtual void SetProxy(const std::string& proxy) = 0;
        // void SetReady(const std::function<void(const Track::Ptr&)> on_ready) = 0;

        virtual void SetVideoReady(const std::function<void(const VideoFormat&)> on_ready)= 0;
        virtual void SetAudioReady(const std::function<void(const AudioFormat&)> on_ready)= 0;

        virtual bool Play(const std::function<bool(const Frame::Ptr &frame)>& on_frame,
                const std::function<void()>& on_stop) = 0;
    };

    Mp4Player::Ptr CreateHttpMp4Player(const char* url, bool repeat = true);
    Mp4Player::Ptr CreateFileMp4Player(const char* filePath, bool repeat = true);
}
#endif